import React from 'react'
import { AjaxSelector } from '../components/common/ajaxSelector'
import { MockSelector } from '../components/common/mockSelector'
import { UserActionSelector } from '../components/common/userActionSelector'
import { Input } from '../components/common/Input'
import { UserActionTypes } from './userActionType'
import { AssertTypes } from './assertType'
import { AssertTypeSelector } from '../components/common/assertTypeSelector'
import basicStyle from '../components/common/basic.scss'
import { CookieSelector } from '../components/common/cookieSelector'
import { StepCollectionSelector } from '../components/common/stepCollectionSelector'
import { WaitTypes } from './waitType'
import { WaitTypeSelector } from '../components/common/waitTypeSelector'
import { renderLogOfElementWithExtSelector } from '../components/common/elementWithExtSelector'

const getWaitTypeFromDetail = detail => {
    if (detail) {
        const { data } = detail
        const { waitType = WaitTypes.htmlElement.key } = data

        return WaitTypes[waitType]
    } else {
        return null
    }
}

export const StepEngine = {
    setCookie: {
        title: '设置Cookie',
        renderEditor: ({ index, data, readOnly, onChangeField }) => {
            const { cookieName } = data

            return (
                <React.Fragment>
                    Cookie：<CookieSelector cookieName={cookieName} onSelectItem={cookie => onChangeField(index, 'cookieName', cookie.name)} readOnly={readOnly} />
                </React.Fragment>
            )
        },
        getRefIdMap: ({ data }) => {
            return {}
        },
        appendExtData: (detail, dataWrapper) => {
            const { data } = detail
            const { cookieName } = data
            const { config } = dataWrapper

            const cookie = config.cookie.find(item => item.name === cookieName)
            if (cookie) {
                return {
                    ...detail,
                    data: {
                        ...detail.data,
                        cookieValue: cookie.value,
                        cookieDomain: cookie.domain
                    }
                }
            } else {
                const err = `not found cookie with name ${cookieName} in config`
                alert(err)
                throw err
            }
        },
        renderLog: ({ data, result }) => {
            const { cookieName, cookie } = data
            return <div className={basicStyle.log_entry}>设置Cookie "{cookieName}"</div>
        }
    },
    mock: {
        title: 'mock Network',
        renderEditor: ({ index, data, readOnly, onChangeField }) => {
            const { ajaxId, mockId, page } = data

            return (
                <React.Fragment>
                    Network：<AjaxSelector ajaxId={ajaxId} onSelectItem={ajax => onChangeField(index, 'ajaxId', ajax.id)} page={page} readOnly={readOnly} />
                    Mock：<MockSelector ajaxId={ajaxId} mockId={mockId} onSelectItem={mock => onChangeField(index, 'mockId', mock.id)} readOnly={readOnly} />
                </React.Fragment>
            )
        },
        getRefIdMap: ({ data }) => {
            const { ajaxId, mockId } = data
            return { ajax: ajaxId, mock: mockId, element: 0 }
        },
        appendExtData: (detail, dataWrapper) => {
            const { data } = detail
            const { ajaxId, mockId } = data
            const { ajax, mock } = dataWrapper

            const ajaxItem = ajax.find(item => item.id === ajaxId)
            const mockItem = mock.find(item => item.id === mockId)

            return {
                ...detail,
                data: {
                    ...detail.data,
                    ajax: ajaxItem,
                    mock: mockItem
                }
            }
        },
        renderLog: ({ data, result }) => {
            const { ajax, mock } = data
            const { url, remark: ajaxRemark } = ajax
            const { remark: mockRemark } = mock
            return <div className={basicStyle.log_entry}>mock <span className={basicStyle.abbr} title={url}>{ajaxRemark}</span> {mockRemark}</div>
        }
    },
    dom: {
        title: '页面操作',
        renderEditor: (detail) => {
            const { index, data, readOnly, onChangeField } = detail
            const { userActionCode } = data

            return (
                <React.Fragment>
                    动作：<UserActionSelector userActionCode={userActionCode} onSelectItem={userAction => onChangeField(index, 'userActionCode', userAction.code)} readOnly={readOnly} />
                    {userActionCode && UserActionTypes[userActionCode]
                        ? UserActionTypes[userActionCode].renderEditor(detail)
                        : (userActionCode ? JSON.stringify(detail) : '')}
                </React.Fragment>
            )
        },
        getRefIdMap: ({ data }) => {
            // 部分action包含元素
            const { elementSelectorId } = data
            return { ajax: 0, mock: 0, element: elementSelectorId || 0 }
        },
        appendExtData: (detail, dataWrapper) => {
            const { data } = detail
            const { elementSelectorId = 0 } = data
            const { element } = dataWrapper

            const elementItem = elementSelectorId ? element.find(item => item.id === elementSelectorId) : null

            return {
                ...detail,
                data: {
                    ...detail.data,
                    element: elementItem
                }
            }
        },
        renderLog: ({ data, result }) => {
            const { userActionCode, text, keyCodes, x, y } = data

            let extra = ''
            switch (userActionCode) {
                case 'type':
                    extra = ` "${text}"`
                    break
                case 'keyPress':
                    extra = ` "${keyCodes.map(item => item.key).join(', ')}`
                    break
                case 'clickAtPostion':
                    extra = `(x: ${x},y: ${y})`
                    break
                default:
                    break;
            }

            return <div className={basicStyle.log_entry}>{userActionCode} {renderLogOfElementWithExtSelector({ data })}{extra}</div>
        }
    },
    wait: {
        title: '等待',
        renderEditor: (detail) => {
            const { readOnly, index, onChangeField } = detail
            const waitType = getWaitTypeFromDetail(detail)

            return (
                <React.Fragment>
                    类型：<WaitTypeSelector inputClassName='width_80px' initValue={waitType.key} onSelectItem={item => onChangeField(index, 'waitType', item.code)} readOnly={readOnly} />
                    {waitType ? waitType.renderEditor(detail) : <div>unknown wait type: {waitType}</div>}
                </React.Fragment>
            )
        },
        getRefIdMap: (detail) => {
            const waitType = getWaitTypeFromDetail(detail)
            return waitType ? waitType.getRefIdMap(detail.data) : { ajax: 0, mock: 0, element: 0 }
        },
        appendExtData: (detail, dataWrapper) => {
            const waitType = getWaitTypeFromDetail(detail)
            return waitType ? waitType.appendExtData(detail, dataWrapper) : detail
        },
        renderLog: (detail) => {
            const waitType = getWaitTypeFromDetail(detail)
            return waitType ? waitType.renderLog(detail) : <div>unknown wait type: {waitType}</div>
        }
    },
    navigate: {
        title: '页面跳转',
        renderEditor: ({ index, page, data, readOnly, onChangeField }) => {
            const { url } = data

            return (
                <React.Fragment>
                    Url：<Input className='width_500px' value={url} placeholder='跳转地址' type='text' onChange={url => onChangeField(index, 'url', url)} readOnly={readOnly} />
                </React.Fragment>
            )
        },
        getRefIdMap: ({ data }) => {
            return { ajax: 0, mock: 0, element: 0 }
        },
        appendExtData: (detail, dataWrapper) => {
            return detail
        },
        renderLog: ({ data, result }) => {
            const { url } = data

            return <div className={basicStyle.log_entry}>页面跳转: {url}</div>
        }
    },
    stepCollection: {
        title: '步骤集',
        renderEditor: ({ index, data, readOnly, onChangeField }) => {
            const { stepCollectionId } = data

            return (
                <React.Fragment>
                    Step Collection：<StepCollectionSelector stepCollectionId={stepCollectionId} onSelectItem={stepCollection => onChangeField(index, 'stepCollectionId', stepCollection.id)} readOnly={readOnly} />
                </React.Fragment>
            )
        },
        getRefIdMap: ({ data }) => {
            return { ajax: 0, mock: 0, element: 0 }
        },
        appendExtData: (detail, dataWrapper) => {
            return detail
        },
        renderLog: ({ data, result }) => {
            throw 'not expected'
        }
    },
    assert: {
        title: '断言',
        renderEditor: (detail) => {
            const { index, data, readOnly, onChangeField } = detail
            const { assertTypeCode } = data

            return (
                <React.Fragment>
                    类型：<AssertTypeSelector assertTypeCode={assertTypeCode} onSelectItem={assertType => onChangeField(index, 'assertTypeCode', assertType.code)} readOnly={readOnly} />
                    {assertTypeCode && AssertTypes[assertTypeCode].renderEditor(detail)}
                </React.Fragment>
            )
        },
        getRefIdMap: ({ data }) => {
            const { assertTypeCode } = data
            return AssertTypes[assertTypeCode].getRefIdMap(data)
        },
        appendExtData: (detail, dataWrapper) => {
            const { data } = detail
            const { elementSelectorId, ajaxId } = data
            const { element, ajax } = dataWrapper

            const ajaxItem = ajax.find(item => item.id === ajaxId)
            const elementItem = elementSelectorId ? element.find(item => item.id === elementSelectorId) : null

            return {
                ...detail,
                data: {
                    ...detail.data,
                    element: elementItem,
                    ajax: ajaxItem
                }
            }
        },
        renderLog: (params) => {
            const { data: { assertTypeCode } } = params
            const assertType = AssertTypes[assertTypeCode]

            return assertType.renderLog(params)
        },
        renderWholeLog: ({ data, result }) => {
            const { assertTypeCode } = data
            const assertType = AssertTypes[assertTypeCode]

            return assertType.renderWholeLog
        },
        getIfResultValid: result => result && result.valid
    },
}